無論有無使用 CloudFront,內容的保護常是提供網站內容的人想要瞭解/達成的目標。
比方說,希望對應的 link 僅在特定時間範圍內有效,才能下載。
有一個方法,是由 CloudFront 提供,可以適用這樣的情境,也是我們今天要介紹的功能,「Signed URL」
概念上,SingedURL 是這樣運作的:
1. 首先你要有一組加密的 Key,其中Private Key 自己保留,Public Key 上傳到 CloudFront 之中。
2. 使用這把 Private Key 加密你要保護的 URL,然後將加密後的字串以 QueryString 的方式附加在原本的 URL 之後。
3. 指定 CloudFront 的對應 Behavior,讓 CloudFront在處理特定 URL Prefix 時需要先嘗試解開你以 Private Key 加密的QueryString 字串,確認相關網址沒被竄改 or 冒用。
4. 如果沒被竄改/冒用--> Let go,繼續後續處理。如果發現加密的字串解不開 or被竄改/冒用了--> 阻攔下來(403)
5. 對了,如果可以放行,相關的回覆內容也可以緩存在 CloudFront 中。
坐著看不如捲起袖子動手,一起來試試吧。以下是一個範例作法。
首先我們要有一個可以使用的網址,我們就用這個吧:
要透過 SingedURL 才能存取的網址: https://dqofozeouve3j.cloudfront.net/0m-HR.mp4
同樣內容,做為參考用: https://dqofozeouve3j.cloudfront.net/static_files/0m-HR.mp4
以下是相關步驟,測試環境是 MacOS,你需要安裝 openssl & perl (這兩個應該內建都有)
$ openssl genrsa -out private_key.pem 2048
$ openssl rsa -pubout -in private_key.pem -out public_key.pem
$ ls -l p*.pem
-rw-r--r-- 1 kgg23 staff 1679 Sep 26 23:20 private_key.pem
-rw-r--r-- 1 kgg23 staff 451 Sep 26 23:20 public_key.pem
這時切換到 CloudFront Console,左側選單選 'Public Keys',點 Create 創立一組新的 Key,並取個名字,比方說 ironman2023-public-key
將前面產出的 public_key.pem 的內容貼到下方的 public_key input text 去。按下創建 key
創建之後,記下這組 public-key 的 key-id(在 SignedURL 中就是 Key-Pair-Id),然後左側選單選到 key-group 去,創建一組Key group
創建一組新的 behavior,URL Path 對應剛的影片檔案,我們設定為 /0m-HR.mp4,要設置 CloudFront 限制存取(Restric Access),並設定其它的 Cache Behavior (ex: 緩存要存多久,要轉發哪些標頭等)
準備一個 Policy 檔案,我們取名叫做 canned-policy,其內容如下。這是一個範例的 Policy,針對對應的URL網址,只要存取時間還沒超過 unix time: 1704038400 (2024.01.01 00:00:00),就可以存取。
(注意 resource 名稱要正確,不然無法存取)
{
"Statement":[
{
"Resource":"https://dqofozeouve3j.cloudfront.net/0m-HR.mp4",
"Condition":{
"DateLessThan":{ "AWS:EpochTime":1704038400 }
}
}
]
}
$ cat canned-policy | tr -d " \t\n\r" | openssl sha1 -sign private_key.pem | openssl base64 | tr -- '+=/' '-_~' | tr -d "\n" | perl -ne 'print "$_\n"'
此時會得到一個字串類似如下,這就是我們的 Signature 值
MgC3QpYzOIPexUKQ1CSW2AOz7KpRnuqkR3F7xBub7L3QrMi1wGES-eXN2tfAPGbvT1HnKSbDE83IqRnaW32HGH-bG7y~wNWyLBrhBiVWRw~6Mw60uaz23MK5RRl8XSlBw0vZc9WDbcSKNimCjmzgJLH8j1Gc4N8KHmvt6xQsV2FXLJeScNGNJp3U-DAVcPCLZEmLzslz0BStTIQRX38YA4RBwGASiaLqGTHltJkELiMx4Qbf~XfWhO70tgESVL0WxNS6jzcpyUYXvGfKEW07aYZbzMmbZwghO1U2Ur9hmRCyy~FdNFpN5pGiMnUIHkM4SJwGcVBi7EnTJUbIA2UKdA__
完成啦!!
使用 curl 驗證也 200 OK!
$ curl -vo /dev/null "https://dqofozeouve3j.cloudfront.net/0m-HR.mp4?Expires=1704038400&Signature=MgC3QpYzOIPexUKQ1CSW2AOz7KpRnuqkR3F7xBub7L3QrMi1wGES-eXN2tfAPGbvT1HnKSbDE83IqRnaW32HGH-bG7y~wNWyLBrhBiVWRw~6Mw60uaz23MK5RRl8XSlBw0vZc9WDbcSKNimCjmzgJLH8j1Gc4N8KHmvt6xQsV2FXLJeScNGNJp3U-DAVcPCLZEmLzslz0BStTIQRX38YA4RBwGASiaLqGTHltJkELiMx4Qbf~XfWhO70tgESVL0WxNS6jzcpyUYXvGfKEW07aYZbzMmbZwghO1U2Ur9hmRCyy~FdNFpN5pGiMnUIHkM4SJwGcVBi7EnTJUbIA2UKdA__&Key-Pair-Id=KADKFBQ2AMLYW"
< HTTP/2 200
< content-type: video/mp4
< content-length: 3616274
< date: Tue, 26 Sep 2023 16:04:50 GMT
< last-modified: Tue, 26 Sep 2023 15:06:20 GMT
< etag: "92574d268be41dde3e65ef4c89306ee1"
< x-amz-server-side-encryption: AES256
< accept-ranges: bytes
< server: AmazonS3
< x-cache: Miss from cloudfront
< via: 1.1 f0c65fa94f0c649f469c108c60821432.cloudfront.net (CloudFront)
< x-amz-cf-pop: TPE52-C1
< x-amz-cf-id: omyEWn1-QV_YB3Wae7vnDZegASCfTYkPNugnZI7saQWdixDgDi9pvw==
p.s. 此時直接存取沒帶 signature 等參數的 url時,會直接報 403.
ex: https://dqofozeouve3j.cloudfront.net/0m-HR.mp4